#ifndef YHAIDA_FASTCGI_H
#define YHAIDA_FASTCGI_H
#include "../../server/base/Utils.h"
#include "../../server/net/TcpConnection.h"
#include "../../server/logging/Logging.h"

#include <map>

namespace yhaida
{

    /**
     * @brief   描述了客户端和Web服务器程序之间传输数据的一种标准。
     *          可以理解为一种编解码器。
     *          可以根据一些参数调用->
     *          注册的回调函数_cb。
     *
     */
    class FastCgiCodec : Utils::nocapyable
    {
    public:
        typedef std::map<std::string, std::string> ParamMap;
        typedef std::function<void(const TcpConnectionPtr &conn,
                                   ParamMap &,
                                   Buffer *)>
            Callback;

    public:
        explicit FastCgiCodec(const Callback &cb)
            : _cb(cb),
              _gotRequest(false),
              _keepConn(false)
        {
        }

        void onMessage(const TcpConnectionPtr &conn,
                       Buffer *buffer,
                       Timestamp recieveTime);

        static void respond(Buffer *response);

        bool getKeepConn() const
        {
            return _keepConn;
        }

    public:
        // kRecordHeader = 8
        //| uint8_t | uint8_t |
        //|      uint16_t     |
        //|      uint16_t     |
        //| uint8_t | uint8_t |
        struct RecordHeader
        {
            uint8_t version;
            uint8_t type;
            uint16_t id;
            uint16_t length;
            // padding 为了使消息8字节对齐，提高传输效率，
            //可以在消息上添加一些字节数来达到消息对齐的目的，
            // paddingLength为添加的字节数，这些字节是无用数据，读出来可以直接丢弃。
            uint8_t padding;
            uint8_t unused;
        };
        enum FcgiType
        {
            kFcgiInvalid = 0,
            kFcgiBeginRequest = 1,
            kFcgiAbortRequest = 2,
            kFcgiEndRequest = 3,
            kFcgiParams = 4,
            kFcgiStdin = 5,
            kFcgiStdout = 6,
            kFcgiStderr = 7,
            kFcgiData = 8,
            kFcgiGetValues = 9,
            kFcgiGetValuesResult = 10,
        };

        enum FcgiRole
        {
            // kFcgiInvalid = 0,
            kFcgiResponder = 1,
            kFcgiAuthorizer = 2,
        };

        enum FcgiConstant
        {
            kFcgiKeepConn = 1,
        };
        const static unsigned kRecordHeader = static_cast<unsigned>(sizeof(FastCgiCodec::RecordHeader));

    private:
        bool parseRequest(Buffer *buffer);
        bool onBeginRequest(const RecordHeader &header, const Buffer *buffer);
        void onStdin(const char *content, uint16_t length);
        bool onParams(const char *content, uint16_t length);
        bool parseAllParams();
        uint32_t readLen();

        static void endStdout(Buffer *buffer);
        static void endRequest(Buffer *buffer);

    private:
        Callback _cb;
        bool _gotRequest;
        bool _keepConn;

        Buffer _stdin;
        Buffer _paramsStream;

        ParamMap _params;
    };
}
#endif